#include "spi_dev_ctl.h"
#include "afe_cmd.h"
#include "spi_cmds.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "usr_cfg.h"
#include "usr_typedef.h"


static const char afe_first_cmds[][FIRST_CMD_CODE_LENGTH] = {
    {'$', 'S', 'A', 'C', 'Q', 'B', 'E', 'G', 0x76, '!'},
    {'$', 'S', 'A', 'C', 'Q', 'S', 'T', 'O', 0x1E, '!'},
    {'$', 'S', 'C', 'A', 'L', 'B', 'E', 'G', 0x71, '!'},
    {'$', 'S', 'C', 'A', 'L', 'S', 'T', 'O', 0x19, '!'},
    {'$', 'G', 'D', 'E', 'V', 'F', 'W', 'R', 0x15, '!'},
    {'$', 'S', 'P', 'W', 'R', 'O', 'F', 'F', 0x27, '!'},
    {'$', 'S', 'P', 'G', 'A', '0', '0', '0', 'F', '!'},
    {'$', 'G', 'P', 'G', 'A', '0', '0', '0', 'F', '!'},
    {'$', 'S', 'M', 'O', 'D', 'A', '0', '0', 'F', '!'},
    {'$', 'S', 'M', 'O', 'D', 'S', '0', '0', 'F', '!'},
    {'$', 'G', 'M', 'O', 'D', 'E', '0', '0', 'F', '!'},
    {'$', 'S', 'S', 'A', 'M', 'P', '0', '0', 'F', '!'},
    {'$', 'G', 'S', 'A', 'M', 'P', '0', '0', 'F', '!'}, // get samp freq
    {'$', 'G', 'S', 'T', 'A', 'T', 'E', '0', 'F', '!'},
};

static const char afe_cmd_ret_table[][CMD_RET_VALID_LENGTH] = {
    {'*', 'O', 'K', '*'},
    {'E', 'R', 'R', '0'},
    {'E', 'R', 'R', '1'},
    {'E', 'R', 'R', '2'},
    {'E', 'R', 'R', '3'},
};

extern spi_cfg_info afe1_spi_dev;

static int afe_cmd_send(afe_dev_info *dev, const char cmd_code[], char ret_code[]);

afe_dev_info afe1_dev = {
	.debug 	= ON,
    .spi 	= &afe1_spi_dev,
    .send 	= afe_cmd_send,
};


static cmd_exe_stat_e check_cmd_exe_stat(const char cmd_ret[])
{
    for (int i = 0; i < 5; i++)
    {
        if (strncmp(cmd_ret + 1, afe_cmd_ret_table[i], 4) == 0)
        {
			return i;
        }
    }

    return exec_ok;
}


static int check_sum_cmp(const char data[], const char chk_sum, uint32_t len)
{
    uint8_t sum = 0;

    for (int i = 0; i < len; i++)
        sum += data[i];
    if (sum == chk_sum)
        return SUCCESS;
    else
        return FAILURE;
}

// 返回负值表示spi通信收发错误，检查spi通信双方协议及硬件。
// -1发送第一条命令错误；-2第一条命令返回值错误，-3发送第二条命令错误；-4第二条命令返回值错误，
// 返回0表示命令正常。
// 返回正值表示命令执行异常，应检查afe硬件。
static int afe_cmd_send(afe_dev_info *dev, const char cmd_code[], char ret_code[])
{
	char cmd_ret1[FIRST_CMD_CODE_LENGTH] = {0};
    char cmd_ret2[SECOND_CMD_CODE_LENGTH] = {0};
    int ret = 0;
    char check_sum = 0;
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};

	strncpy(cmd, cmd_code, FIRST_CMD_CODE_LENGTH);

	// 命令检查
	if (cmd[0] != CMD_CODE_HEAD || cmd[FIRST_CMD_CODE_LENGTH - 1] != CMD_CODE_TAIL)
		return AFE_SPI_FIRST_CMD_ERR;
	
    for (int i = 1; i < FIRST_CMD_CODE_LENGTH - 2; i++)
        check_sum += cmd[i];
    cmd[FIRST_CMD_CODE_LENGTH - 2] = check_sum;
	
    // 发送指令命令码
    ret = spi_transfer(dev->spi, cmd, cmd_ret1, sizeof(cmd_ret1));
    if (ret == FAILURE)
        return AFE_SPI_FIRST_CMD_ERR;

    if (dev->debug == ON)
    {
		printf("%s is afe first cmd send\n", cmd);
		printf("%s is afe first cmd send return\n", cmd_ret1);
    }
	
    // 检查返回值1  台架设备为 ： "#R******N!"
    ret = strncmp(cmd_ret1, FIRST_CMD_RET_STR, FIRST_CMD_CODE_LENGTH);
    if (ret != 0)
        return AFE_SPI_FIRST_RTN_ERR;

    // 发送返回命令码
    ret = spi_transfer(dev->spi, "+++++++", cmd_ret2, sizeof(cmd_ret2));	
	if (ret == FAILURE)
        return AFE_SPI_SECOND_CMD_ERR;
    if (dev->debug == ON)
    {
        for (uint8_t j = 0; j < sizeof(cmd_ret2) - 2; j++)
            putchar(cmd_ret2[j]);
        printf(" %#x", cmd_ret2[sizeof(cmd_ret2) - 2]);
        printf(" %#x ", cmd_ret2[sizeof(cmd_ret2) - 1]);
		printf("is afe second cmd send return\n");
    }
	
    // 检查包头包尾
    if (cmd_ret2[0] != CMD_RET_CODE_HEAD || cmd_ret2[SECOND_CMD_CODE_LENGTH - 1] != CMD_RET_CODE_TAIL)
        return AFE_SPI_SECOND_RTN_ERR;

    // 检查返回值校验和
    if (check_sum_cmp(cmd_ret2 + 1, cmd_ret2[SECOND_CMD_CODE_LENGTH - 2], 4) != 0)
        return AFE_SPI_SECOND_RTN_ERR;

    // 检查指令执行状态
   // ret = check_cmd_exe_stat(cmd_ret2); // 0：正常执行  1，2，3，4为对应错误码
    //if (ret == exec_ok)
   // {
   //     memcpy(ret_code, cmd_ret2 + 1, 4);
    //}
    memcpy(ret_code, cmd_ret2 + 1, 4);

    return SUCCESS;
}



int afe_acq_begin(afe_dev_info *afe_dev)
{
	cmd_exe_stat_e ret;
    char ret_val[4] = {0};
	
    afe_dev->send(afe_dev, afe_first_cmds[s_acq_begin], ret_val);
	ret = check_cmd_exe_stat(ret_val);
	if (ret == exec_ok)
		return SUCCESS;
	else
		return FAILURE;
}

int afe_acq_stop(afe_dev_info *afe_dev)
{
	cmd_exe_stat_e ret;
    char ret_val[4] = {0};
	
    afe_dev->send(afe_dev, afe_first_cmds[s_acq_stop], ret_val);
	ret = check_cmd_exe_stat(ret_val);
	if (ret == exec_ok)
		return SUCCESS;
	else
		return FAILURE;
}

int afe_tib_begin(afe_dev_info *afe_dev)
{
	cmd_exe_stat_e ret;
    char ret_val[4] = {0};

	afe_dev->send(afe_dev, afe_first_cmds[s_cal_begin], ret_val);
	ret = check_cmd_exe_stat(ret_val);
	if (ret == exec_ok)
		return SUCCESS;
	else
		return FAILURE;
}

int afe_tib_stop(afe_dev_info *afe_dev)
{
	cmd_exe_stat_e ret;
    char ret_val[4] = {0};

	afe_dev->send(afe_dev, afe_first_cmds[s_cal_stop], ret_val);
	ret = check_cmd_exe_stat(ret_val);
	if (ret == exec_ok)
		return SUCCESS;
	else
		return FAILURE;
}

void afe_get_fw(afe_dev_info *afe_dev, char afe_fw[])
{
	afe_dev->send(afe_dev, afe_first_cmds[g_afe_fw], afe_fw);
}


int afe_pwr_off(afe_dev_info *afe_dev)
{
    char ret_val[4] = {0};
    return afe_dev->send(afe_dev, afe_first_cmds[s_pwr_off], ret_val);
}


int afe_set_chx_gain(afe_dev_info *afe_dev, uint16_t chx, pga_gain_e gain)
{
    int ret = 0;
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[s_pga_gain], FIRST_CMD_CODE_LENGTH);
    cmd[7] = gain;
    for (int i = 0; i < ACC_CH_TOTAL; i++)
    {
        if (GET_REG_BIT(chx, i))
        {
            if (i < 10)
                cmd[6] = i + 0x30; // ch0~ch9  -->  '0'~'9'
            else
                cmd[6] = i + 0x37; // ch10~ch15  -->  'A'~'F'
            ret = afe_dev->send(afe_dev, cmd, ret_val);
			break;
        }
    }

    return ret;
}


int afe_get_chx_gain(afe_dev_info *afe_dev, uint16_t chx, pga_gain_e *gain)
{
    int ret = 0;
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[g_pga_gain], FIRST_CMD_CODE_LENGTH);

    for (int i = 0; i < ACC_CH_TOTAL; i++)
    {
        if (GET_REG_BIT(chx, i))
        {
            if (i < 10)
                cmd[6] = i + 0x30; // ch0~ch9  -->  '0'~'9'
            else
                cmd[6] = i + 0x37; // ch10~ch15  -->  'A'~'F'
            ret = afe_dev->send(afe_dev, cmd, ret_val);
            break;
        }
    }

    if (ret == SUCCESS)
        *gain = ret_val[3];

    return ret;
}


int afe_set_chx_mode(afe_dev_info *afe_dev, uint16_t chx, chx_mode_e mode)
{
    int ret = 0;
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[s_chx_mode], FIRST_CMD_CODE_LENGTH);
    cmd[7] = mode;
    for (int i = 0; i < ACC_CH_TOTAL; i++)
    {
        if (GET_REG_BIT(chx, i))
        {
            if (i < 10)
                cmd[6] = i + 0x30; // ch0~ch9  -->  '0'~'9'int
            else
                cmd[6] = i + 0x37; // ch10~ch15  -->  'A'~'F'
            ret = afe_dev->send(afe_dev, cmd, ret_val);
            break;
        }
    }

    return ret;
}


int afe_get_chx_mode(afe_dev_info *afe_dev, uint16_t chx, chx_mode_e *mode)
{
    int ret = 0;
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[g_chx_mode], FIRST_CMD_CODE_LENGTH);
    for (int i = 0; i < ACC_CH_TOTAL; i++)
    {
        if (GET_REG_BIT(chx, i))
        {
            if (i < 10)
                cmd[6] = i + 0x30; // ch0~ch9  -->  '0'~'9'
            else
                cmd[6] = i + 0x37; // ch10~ch15  -->  'A'~'F'
            ret = afe_dev->send(afe_dev, cmd, ret_val);
            break;
        }
    }

    if (ret == SUCCESS)
        *mode = ret_val[3];

    return ret;
}


int afe_set_spdx_mode(afe_dev_info *afe_dev, uint16_t spdx, spdx_mode_e mode)
{
	int ret = 0;
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[s_spdx_mode], FIRST_CMD_CODE_LENGTH);
    cmd[7] = mode;

	for (int i = 0; i < SPD_CH_TOTAL; i++)
    {
        if (GET_REG_BIT(spdx, i))
        {
            cmd[6] = i + 0x30; // ch0~ch9  -->  '0'~'9'int
            ret = afe_dev->send(afe_dev, cmd, ret_val);
            break;
        }
    }
	
	return ret;
}


int afe_set_samp_freq(afe_dev_info *afe_dev, samp_freq_e samp_freq)
{
    char ret_val[4] = {0};
    char cmd[FIRST_CMD_CODE_LENGTH] = {0};
	
    strncpy(cmd, afe_first_cmds[s_afe_samp], FIRST_CMD_CODE_LENGTH);
    cmd[7] = samp_freq;

    return afe_dev->send(afe_dev, cmd, ret_val);
}


int afe_get_samp_freq(afe_dev_info *afe_dev, samp_freq_e *samp_freq)
{
    char ret_val[4] = {0};
    int ret = 0;

    ret = afe_dev->send(afe_dev, afe_first_cmds[g_afe_samp], ret_val);

    if (ret == SUCCESS)
        *samp_freq = ret_val[3];

    return ret;
}



int afe_get_state(afe_dev_info *afe_dev, uint8_t afe_state[])
{
    char ret_val[4] = {0};
    int ret = 0;

    ret = afe_dev->send(afe_dev, afe_first_cmds[g_afe_stat], ret_val);
    if (ret == 0)
    {
        afe_state[0] = ret_val[0];
        afe_state[1] = ret_val[1];
        afe_state[2] = ret_val[2];
        afe_state[3] = ret_val[3];
    }

    return ret;
}


